package 多线程.Test;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Condition是被绑定到Lock上的，必须使用lock.newCondition()才能创建一个Condition。
 * 从上面的代码可以看出，Synchronized能实现的通信方式，Condition都可以实现，
 * 功能类似的代码写在同一行中。这样解题思路就和第一种方法基本一致，只是采用的方法不同。
 *
 * wait()和await()都是用于线程间的同步和协调的方法，但是它们在不同的上下文和语境中使用。
 *
 * wait()是Java中Object类的一个方法，它用于在对象级别上进行线程同步和通信。以下是wait()的一些特点：
 *
 * wait()方法必须在同步的代码块或同步方法中调用，即在使用synchronized关键字修饰的代码块或方法中。
 * 当线程调用wait()方法时，它会释放对象的锁，并进入等待状态，直到其他线程调用相同对象上的notify()或notifyAll()方法来唤醒等待的线程。
 * 线程被唤醒后，它会重新尝试获取对象的锁，并继续执行。
 * wait()方法可以带有超时参数，指定线程等待的最长时间，在超时时间内如果没有被唤醒，线程会自动苏醒。
 * await()是Java中Condition接口的一个方法，它用于在更高级别的线程同步和通信场景中使用，通常与Lock对象一起使用。以下是await()的一些特点：
 *
 * await()方法必须在获取了相应的Lock对象之后调用，一般通过调用Lock对象的lock()方法来获得锁。
 * 当线程调用await()方法时，它会释放当前获得的锁，并进入等待状态，直到其他线程调用相同的Condition对象上的signal()或signalAll()方法来唤醒等待的线程。
 * 线程被唤醒后，它会尝试重新获取之前释放的锁，并继续执行。
 * await()方法也可以带有超时参数，指定线程等待的最长时间，在超时时间内如果没有被唤醒，线程会自动苏醒。
 * 总的来说，wait()方法是在对象级别上进行线程同步和通信，而await()方法是在更高级别的锁和条件对象上进行线程同步和通信。
 * await()方法提供了更灵活的等待和唤醒机制，同时可以与Lock对象结合使用，提供更精细的线程控制。
 */
public class ABC_Condition {
    private static Lock lock = new ReentrantLock();
    private static Condition A = lock.newCondition();
    private static Condition B = lock.newCondition();
    private static Condition C = lock.newCondition();
 
    private static int count = 0;
 
    static class ThreadA extends Thread {
        @Override
        public void run() {
            try {
                lock.lock();
                for (int i = 0; i < 10; i++) {
                    while (count % 3 != 0)//注意这里是不等于0，也就是说在count % 3为0之前，当前线程一直阻塞状态
                    {
                        A.await(); // A释放lock锁
                    }
                    System.out.println("A");
                    count++;
                    B.signal(); // A执行完唤醒B线程
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                System.out.println("A解锁");
                lock.unlock();
            }
        }
    }
 
    static class ThreadB extends Thread {
        @Override
        public void run() {
            try {
                lock.lock();
                for (int i = 0; i < 10; i++) {
                    while (count % 3 != 1) {
                        B.await();// B释放lock锁，当前面A线程执行后会通过B.signal()唤醒该线程
                    }
                    System.out.println("B");
                    count++;
                    C.signal();// B执行完唤醒C线程
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                System.out.println("B解锁");
                lock.unlock();
            }
        }
    }
 
    static class ThreadC extends Thread {
        @Override
        public void run() {
            try {
                lock.lock();
                for (int i = 0; i < 10; i++) {
                    while (count % 3 != 2) {
                        C.await();// C释放lock锁，当前面B线程执行后会通过C.signal()唤醒该线程
                    }
                    System.out.println("C");
                    System.out.println("----------");
                    count++;
                    A.signal();// C执行完唤醒A线程
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                System.out.println("C解锁");
                lock.unlock();
            }
        }
    }
 
    public static void main(String[] args) throws InterruptedException {
        //这里故意把A线程写后边
        new ThreadB().start();
        new ThreadB().start();
        new ThreadC().start();
        new ThreadC().start();
        new ThreadA().start();
        new ThreadA().start();
    }
}